//-----------------------------------------------------------------------------
// Torque 3D
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------


/// Calculate fog based on a start and end positions in worldSpace.
float computeSceneFog(  float3 startPos,
                        float3 endPos,
                        float fogDensity,
                        float fogDensityOffset,
                        float fogHeightFalloff )
{      
   float f = length( startPos - endPos ) - fogDensityOffset;
   float h = 1.0 - ( endPos.z * fogHeightFalloff );  
   return exp( -fogDensity * f * h );  
}


/// Calculate fog based on a start and end position and a height.
/// Positions do not need to be in worldSpace but height does.
float computeSceneFog( float3 startPos,
                       float3 endPos,
                       float height,
                       float fogDensity,
                       float fogDensityOffset,
                       float fogHeightFalloff )
{
   float f = length( startPos - endPos ) - fogDensityOffset;
   float h = 1.0 - ( height * fogHeightFalloff );
   return exp( -fogDensity * f * h );
}


/// Calculate fog based on a distance, height is not used.
float computeSceneFog( float dist, float fogDensity, float fogDensityOffset )
{
   float f = dist - fogDensityOffset;
   return exp( -fogDensity * f );
}


/// Convert a float4 uv in viewport space to render target space.
float2 viewportCoordToRenderTarget( float4 inCoord, float4 rtParams )
{   
   float2 outCoord = inCoord.xy / inCoord.w;
   outCoord = ( outCoord * rtParams.zw ) + rtParams.xy;  
   return outCoord;
}


/// Convert a float2 uv in viewport space to render target space.
float2 viewportCoordToRenderTarget( float2 inCoord, float4 rtParams )
{   
   float2 outCoord = ( inCoord * rtParams.zw ) + rtParams.xy;
   return outCoord;
}


/// The number of additional substeps we take when refining
/// the results of the offset parallax mapping function below.
///
/// You should turn down the number of steps if your needing
/// more performance out of your parallax surfaces.  Increasing
/// the number doesn't yeild much better results and is rarely
/// worth the additional cost.
///
#define PARALLAX_REFINE_STEPS 3

/// Performs fast parallax offset mapping using 
/// multiple refinement steps.
///
/// @param texMap The texture map whos alpha channel we sample the parallax depth.
/// @param texCoord The incoming texture coordinate for sampling the parallax depth.
/// @param negViewTS The negative view vector in tangent space.
/// @param depthScale The parallax factor used to scale the depth result.
///
float2 parallaxOffset( sampler2D texMap, float2 texCoord, float3 negViewTS, float depthScale )
{
   float depth = tex2D( texMap, texCoord ).a;
   float2 offset = negViewTS.xy * ( depth * depthScale );

   for ( int i=0; i < PARALLAX_REFINE_STEPS; i++ )
   {
      depth = ( depth + tex2D( texMap, texCoord + offset ).a ) * 0.5;
      offset = negViewTS.xy * ( depth * depthScale );
   }

   return offset;
}


/// The maximum value for 16bit per component integer HDR encoding.
static const float HDR_RGB16_MAX = 100.0;

/// The maximum value for 10bit per component integer HDR encoding.
static const float HDR_RGB10_MAX = 4.0;

/// Encodes an HDR color for storage into a target.
float3 hdrEncode( float3 sample )
{
   #if defined( TORQUE_HDR_RGB16 )

      return sample / HDR_RGB16_MAX;

   #elif defined( TORQUE_HDR_RGB10 ) 

      return sample / HDR_RGB10_MAX;

   #else

      // No encoding.
      return sample;

   #endif
}

/// Encodes an HDR color for storage into a target.
float4 hdrEncode( float4 sample )
{
   return float4( hdrEncode( sample.rgb ), sample.a );
}

/// Decodes an HDR color from a target.
float3 hdrDecode( float3 sample )
{
   #if defined( TORQUE_HDR_RGB16 )

      return sample * HDR_RGB16_MAX;

   #elif defined( TORQUE_HDR_RGB10 )

      return sample * HDR_RGB10_MAX;

   #else

      // No encoding.
      return sample;

   #endif
}

/// Decodes an HDR color from a target.
float4 hdrDecode( float4 sample )
{
   return float4( hdrDecode( sample.rgb ), sample.a );
}

/// Returns the luminance for an HDR pixel.
float hdrLuminance( float3 sample )
{
   // There are quite a few different ways to
   // calculate luminance from an rgb value.
   //
   // If you want to use a different technique
   // then plug it in here.
   //

   ////////////////////////////////////////////////////////////////////////////
   //
   // Max component luminance.
   //
   //float lum = max( sample.r, max( sample.g, sample.b ) );

   ////////////////////////////////////////////////////////////////////////////
   // The perceptual relative luminance.
   //
   // See http://en.wikipedia.org/wiki/Luminance_(relative)
   //
   const float3 RELATIVE_LUMINANCE = float3( 0.2126, 0.7152, 0.0722 );
   float lum = dot( sample, RELATIVE_LUMINANCE );
  
   ////////////////////////////////////////////////////////////////////////////
   //
   // The average component luminance.
   //
   //const float3 AVERAGE_LUMINANCE = float3( 0.3333, 0.3333, 0.3333 );
   //float lum = dot( sample, AVERAGE_LUMINANCE );

   return lum;
}
